﻿using System;
using System.Data.SqlClient;
using System.Globalization;
using JTLeigh.Commerce.Spencer.Core.Common;
using JTLeigh.Commerce.Spencer.Core.Data.Exceptions;

namespace JTLeigh.Commerce.Spencer.Core.Data
{

	/// <summary>
	/// Transforms database-specific exceptions to database-agnostic exceptions.
	/// </summary>
	/// <remarks>
	/// <para>
	/// <see cref="DatabaseExceptionTransformer"/> is used to transform exceptions specific to a 
	/// single database or client library (such as <see cref="SqlException"/>) to agnostic ones
	/// used throughout the application (such as <see cref="PrimaryKeyViolationException"/>).  All
	/// data access code should use <see cref="DatabaseExceptionTransformer"/> to transform 
	/// exceptions before handling them.  No code should handle database-specific exceptions.
	/// </para>
	/// <para>
	/// This is an important part of our database abstraction layer.
	/// </para>
	/// </remarks>
	public static class DatabaseExceptionTransformer
	{

		#region Methods

		/// <summary>
		/// Transforms the original database-specific exception to a database-agnostic exception.
		/// </summary>
		/// <param name="originalException">The original <see cref="Exception"/>.</param>
		/// <returns>The transformed exception from the <see cref="JTLeigh.Commerce.Spencer.Core.Data.Exceptions"/> 
		/// namespace, or the original exception if it couldn't be transformed.</returns>
		public static Exception Transform(Exception originalException)
		{
			SqlException sqlException;

			Safety.AssertArgumentNotNull("originalException", originalException);

			sqlException = originalException as SqlException;
			if (sqlException != null)
			{
				switch (sqlException.Number)
				{
					case 2627:
						return new PrimaryKeyViolationException(GetMessage(sqlException), sqlException);
				}
			}
			return originalException;
		}

		#endregion // Methods

		#region Implementation

		private static string GetMessage(SqlException sqlException)
		{
			Safety.AssertArgumentNotNull("sqlException", sqlException);

			return String.Format(CultureInfo.InvariantCulture, "{0}({1}): {2}", sqlException.Procedure, sqlException.LineNumber, sqlException.Message);
		}

		#endregion // Implementation

	}

}
